#pragma once
#include "base.pb.h"
#include "file.pb.h"

#include "etcd.hpp"
#include "utils.hpp"

#include <filesystem>

#include <brpc/server.h>
class FileServiceImpl : public chat_system::FileService
{
public:
    using ptr = std::shared_ptr<FileServiceImpl>;

    FileServiceImpl(const std::string_view& path)
        : _file_path(path)
    {
        if(_file_path.empty() == false)
        {
            //如果路径不存在，则创建目录
            if(!std::filesystem::exists(_file_path))
            {
                std::error_code ec;
                std::filesystem::create_directories(_file_path, ec);
                if(ec)
                {
                    LOG_ERROR("创建文件目录失败: {}, 错误: {}", _file_path, ec.message());
                    throw std::runtime_error("创建文件目录失败");
                }
                LOG_INFO("创建文件目录成功: {}", _file_path);
            }
            //如果路径不是以/结尾，则添加/
            if(_file_path.back() != '/')
            {
                _file_path.push_back('/');
            }
        }
        
    }
    FileServiceImpl() = default;
    virtual void GetSingleFile(google::protobuf::RpcController* controller,
                            const chat_system::GetSingleFileReq* request,
                            chat_system::GetSingleFileRsp* response,
                            google::protobuf::Closure* done) override
    {
        brpc::ClosureGuard guard(done);
        //文件id即是文件名
        std::string file_id = request->file_id();
        std::string file = _file_path + file_id;

        response->set_request_id(request->request_id());
        if(!std::filesystem::exists(file))
        {
            response->set_success(false);
            response->set_errmsg("该文件不存在");            
            LOG_ERROR("文件不存在: {}", file);
            return;
        }

        std::string content;
        bool success = readFile(file, content);
        response->set_success(success);
        if(!success)
        {
            response->set_errmsg("读取文件失败");
            LOG_ERROR("读取文件失败: {}", file);
            return;            
        }
        LOG_INFO("文件读取成功: {}", file);
        //设置响应数据
        response->set_errmsg("success");
        response->mutable_file_data()->set_file_id(file_id);
        response->mutable_file_data()->set_file_content(content);
    }


    virtual void GetMultiFile(google::protobuf::RpcController* controller,
                            const chat_system::GetMultiFileReq* request,
                            chat_system::GetMultiFileRsp* response,
                            google::protobuf::Closure* done) override
    {
        brpc::ClosureGuard guard(done);
        int size = request->file_id_list_size();
        response->set_request_id(request->request_id());
        for(int i = 0; i < size; ++i)
        {
            std::string file_id = request->file_id_list(i);
            std::string file = _file_path + file_id;

            if(!std::filesystem::exists(file))
            {
                response->set_success(false);
                response->set_errmsg("该文件不存在");            
                LOG_ERROR("文件不存在: {}", file);
                return;
            }

            std::string content;
            bool success = readFile(file, content);
            LOG_DEBUG("---{}---", success);
            LOG_DEBUG("111111111111111111111111111111111111");
            response->set_success(success);
            if(!success)
            {
                response->set_errmsg("读取文件失败");
                LOG_ERROR("读取文件失败: {}", file);
                return;            
            }

            LOG_INFO("文件读取成功: {}", file);
            //设置响应数据
            LOG_DEBUG("文件id: {}, 内容长度: {}", file_id, content.size());
            chat_system::FileDownloadData file_data;
            file_data.set_file_id(file_id);
            file_data.set_file_content(content);
            response->mutable_file_data()->emplace(file_id, file_data);
        }
        response->set_success(true);
        response->set_errmsg("success");
    }                           
    virtual void PutSingleFile(google::protobuf::RpcController* controller,
                            const chat_system::PutSingleFileReq* request,
                            chat_system::PutSingleFileRsp* response,
                            google::protobuf::Closure* done) override
    {
        brpc::ClosureGuard guard(done);
        response->set_request_id(request->request_id());
        chat_system::FileUploadData file_data = request->file_data();     
        std::string file_id = uuid();
        std::string file = _file_path + file_id;
        LOG_DEBUG("id, {}", request->request_id());
        LOG_DEBUG("{}, {}", file_data.file_name(), file_data.file_content());
        assert(file_data.file_content() == request->file_data().file_content());
        //写入文件
        bool success = writeFile(file, file_data.file_content());   
        response->set_success(success);
        if(!success)
        {
            response->set_errmsg("写入文件失败");
            LOG_ERROR("写入文件失败: {}", file);
            return;            
        }
        LOG_INFO("文件写入成功: {}", file);
        //设置响应数据
        response->set_errmsg("success");
        response->mutable_file_info()->set_file_id(file_id);
        response->mutable_file_info()->set_file_name(file_data.file_name());
        response->mutable_file_info()->set_file_size(file_data.file_size());
        
    }
    virtual void PutMultiFile(google::protobuf::RpcController* controller,
                            const chat_system::PutMultiFileReq* request,
                            chat_system::PutMultiFileRsp* response,
                            google::protobuf::Closure* done) override
    {
        brpc::ClosureGuard guard(done);
        response->set_request_id(request->request_id());
        //获取文件个数
        int size = request->file_data_size();
        for(int i = 0; i < size; ++i)
        {
            chat_system::FileUploadData file_data = request->file_data(i); 
            std::string file_id = uuid();
            std::string file = _file_path + file_id;
            //写入文件
            bool success = writeFile(file, file_data.file_content());   
            response->set_success(success);
            if(!success)
            {
                response->set_errmsg("写入文件失败");
                LOG_ERROR("写入文件失败: {}", file);
                return;            
            }
            LOG_INFO("文件写入成功: {}", file);
            //设置响应数据
            chat_system::FileMessageInfo file_info;
            file_info.set_file_id(file_id);
            file_info.set_file_name(file_data.file_name());
            file_info.set_file_size(file_data.file_size());
            response->mutable_file_info()->Add(std::move(file_info));
        }
        response->set_errmsg("success");
    }                       
private:
    std::string _file_path;
};


class FileServer
{
public:
    using ptr = std::shared_ptr<FileServer>;
    FileServer(FileServiceImpl::ptr file_service_impl,
                 Registry::ptr registry_client,
                 std::shared_ptr<brpc::Server> server)
        : _file_service_impl(file_service_impl)
        , _registry_client(registry_client)
        , _server(server)
    {}
    void start()
    {
        LOG_INFO("文件服务已启动");
        _server->RunUntilAskedToQuit();
    }

private:
    FileServiceImpl::ptr _file_service_impl;
    Registry::ptr _registry_client;
    std::shared_ptr<brpc::Server> _server;

};


class FileServerBuilder
{
public:

    void make_file_service_impl(const std::string_view& path = "")
    {
        _file_service_impl = std::make_shared<FileServiceImpl>(path);
        if(_file_service_impl == nullptr)
        {
            LOG_ERROR("文件服务实例创建失败");
            return;
        }
        LOG_INFO("文件服务实例创建成功");
    }



    void make_reg_object(const std::string &etcd_host, const std::string& service_name, const std::string service_host)
    {
        _registry_client = std::make_shared<Registry>(etcd_host);
        bool success = _registry_client->registry(service_name, service_host);
        if(!success)
        {
            LOG_ERROR("注册服务到etcd失败");
            return;
        }
        LOG_INFO("注册服务{} - {}到etcd成功", service_name, service_host);
    }


    void make_rpc_object(uint16_t port, int32_t timeout, uint8_t num_threads)
    {
        logging::LoggingSettings tmp_log;
        tmp_log.logging_dest = logging::LOG_TO_NONE;
        logging::InitLogging(tmp_log);
        _server = std::make_shared<brpc::Server>();
        int ret = _server->AddService(_file_service_impl.get(), brpc::SERVER_DOESNT_OWN_SERVICE);
        if(ret < 0)
        {
            LOG_ERROR("注册服务失败");
            return;
        }
        brpc::ServerOptions options;
        options.idle_timeout_sec = timeout;
        options.num_threads = num_threads;
        ret = _server->Start(port, &options);
        if(ret < 0)
        {
            LOG_ERROR("启动服务器失败");
            return;  
        }
    }


    FileServer::ptr build()
    {
        if(_file_service_impl == nullptr)
        {
            LOG_ERROR("文件服务实例未创建");
            return nullptr;
        }
        if(_registry_client == nullptr)
        {
            LOG_ERROR("注册中心对象未创建");
            return nullptr;
        }
        if(_server == nullptr)
        {
            LOG_ERROR("RPC服务器对象未创建");
            return nullptr;
        }
        FileServer::ptr file_server = std::make_shared<FileServer>(_file_service_impl, _registry_client, _server);
        return file_server;
    }

private:
    FileServiceImpl::ptr _file_service_impl;
    Registry::ptr _registry_client;
    std::shared_ptr<brpc::Server> _server;

};